﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SilverlightApplication1;
using Microsoft.Silverlight.Testing;
using System.Windows.Threading;
using System.Threading;
using System.Linq;
using LINQAmazonProvider;

namespace Test1
{
    [TestClass]
    public class Test_Class : SilverlightTest
    {
        private Dispatcher _mainDispatcher;
        public enum QueryOptions { SIMPLE_QUERY, DOUBLE_QUERY, FIRST, LAST };
        public enum PriceRangeOptions { LESS, UPPER, BETWEEN };
        public QueryOptions QueryOption = QueryOptions.SIMPLE_QUERY;
        public IQueryable<Common.DataTypes.Book> Query { get; set; }
        public IQueryable<Common.DataTypes.Book> Query2 { get; set; }
        public List<Common.DataTypes.Book> Result { get; set; }
        public List<Common.DataTypes.Book> Result2 { get; set; }
        public Common.DataTypes.Book BookResult { get; set; }
        public string AmazonKey = "0TD9TEYEE3NDY01M6D02";
        public string QueryLanguage = "espaniol";
        private const int NOT_VALUE = -1;

        [TestInitialize]
        public void PreparePage()
        {
            this._mainDispatcher = MainDispatcher.Current;
        }

        string CleanWord(string word) {
            string[] charactersToIgnore = { ",", ":", ".", ";", "-", "+", "=", "_", "ñ", "!", "¡", "(", ")", "¿", "?", "'", "\"", "&", "#", "^", "[", "]", "{", "}", "&", "$", "@" };
            string[] toReplace = { "á", "é", "í", "ó", "ú", "ñ" };
            string[] replacements = { "a", "e", "i", "o", "u", "n" };

            string result = word.ToLower();

            foreach (string charToIngore in charactersToIgnore) {
                result = result.Replace(charToIngore, " ");
            }

            for (int i = 0; i < toReplace.Count(); i++) {
                result = result.Replace(toReplace[i], replacements[i]);
            }

            return (result);
        }

        private string[] GetSubstrings(string word1) {
            int wordLenght = word1.Length;
            float approvedPercent = 0.8F;
            int substringSize = Convert.ToInt32(Math.Ceiling(approvedPercent * wordLenght));
            string[] result = new string[wordLenght - substringSize + 1];

            if (substringSize != wordLenght)
            {
                for (int i = substringSize; i <= wordLenght; i++)
                {
                    result[i - substringSize] = word1.Substring(0, i);
                }
            }
            else {
                result[0] = word1;
            }

            return (result);
        }

        private bool Contains(string word1, string word2)
        {
            bool approved = false;
            string[] arrayWord1 = CleanWord(word1).Split(" ".ToCharArray());
            List<string> listWord2 = new List<string>(CleanWord(word2).Split(" ".ToCharArray()));
            int numberOfContains = 0;
            float approvedPercent = 0.75F;

            foreach (string word in arrayWord1) {
                if (listWord2.Contains(word))
                {
                    numberOfContains++;
                }
                else {
                    string[] substrings = GetSubstrings(word);
                    bool contains = false;
                    int numberOfSubstrings = substrings.Count();
                    int i = 0;

                    while ((i < numberOfSubstrings) && !contains) {
                        contains = listWord2.Contains(substrings[i]);
                        i++;
                    }

                    if (contains) {
                        numberOfContains++;
                    }
                }
            }

            if (numberOfContains > 0) {
                approved = ((arrayWord1.Count() / numberOfContains) > approvedPercent);
            }

            return (approved);
        }


        private bool BookPriceInRange (Common.DataTypes.Book book, int bottomLimit, int upLimit, PriceRangeOptions priceRange){
            bool isInRange = false;
            bool anyValue = false;
            List<int> bookPrices = GetBookPrices(book);
            int i = 0;

            if (priceRange == PriceRangeOptions.LESS){
                while (i < bookPrices.Count && !isInRange) {
                    isInRange = ((bookPrices[i] != NOT_VALUE) && bookPrices[i] <= upLimit);
                    if (!anyValue) {
                        anyValue = (bookPrices[i] != NOT_VALUE);
                    }
                    i++;
                }
            }
            else if (priceRange == PriceRangeOptions.UPPER)
            {
                while (i < bookPrices.Count && !isInRange)
                {
                    isInRange = ((bookPrices[i] != NOT_VALUE) && bookPrices[i] >= bottomLimit);
                    if (!anyValue)
                    {
                        anyValue = (bookPrices[i] != NOT_VALUE);
                    }
                    i++;
                }
            }
            else {
                while (i < bookPrices.Count && !isInRange)
                {
                    isInRange = ((bookPrices[i] != NOT_VALUE) && bookPrices[i] >= bottomLimit && bookPrices[i] <= upLimit);
                    if (!anyValue)
                    {
                        anyValue = (bookPrices[i] != NOT_VALUE);
                    }
                    i++;
                }
            }

            if (!anyValue) {
                isInRange = true;
            }

            return (isInRange);
        }

        private List<int> GetBookPrices (Common.DataTypes.Book book){
            List<int> result = new List<int>();

            // Add result price
            result.Add(GetListPriceDataAmount(book.ListPrice));

            // Add offers prices if available
            if (book.OfferSummary != null){
                Common.DataTypes.ItemOfferSummaryData offers = book.OfferSummary;
                
                result.Add(GetListPriceDataAmount(offers.LowestCollectiblePrice));
                result.Add(GetListPriceDataAmount(offers.LowestNewPrice));
                result.Add(GetListPriceDataAmount(offers.LowestRefurbishedPrice));
                result.Add(GetListPriceDataAmount(offers.LowestUsedPrice));
            }

            return (result);
        }

        private int GetListPriceDataAmount(Common.DataTypes.ListPriceData price)
        {
            int result = NOT_VALUE;

            if (price != null)
            {
                result = price.Amount;
            }

            return (result);
        }

        private int GetBookLowerPrice(Common.DataTypes.Book book) {
            int result = NOT_VALUE;
            List<int> pricesBook = GetBookPrices(book);

            foreach (int price in pricesBook) {
                if (price != NOT_VALUE) {
                    if (result == NOT_VALUE)
                    {
                        result = price;
                    }
                    else {
                        if (result > price) {
                            result = price;
                        }
                    }
                }
            }

            return (result);
        }

        private int GetBookMaxPrice(Common.DataTypes.Book book)
        {
            int result = NOT_VALUE;
            List<int> pricesBook = GetBookPrices(book);

            foreach (int price in pricesBook)
            {
                if (price != NOT_VALUE)
                {
                    if (result == NOT_VALUE)
                    {
                        result = price;
                    }
                    else
                    {
                        if (result < price)
                        {
                            result = price;
                        }
                    }
                }
            }

            return (result);
        }

        private bool IsBookPriceLower(Common.DataTypes.Book book1, Common.DataTypes.Book book2) {
            bool isLower = true;
            int lowerBookPrice1 = GetBookLowerPrice(book1);
            int lowerBookPrice2 = GetBookLowerPrice(book2);

            if (lowerBookPrice1 != NOT_VALUE && lowerBookPrice2 != NOT_VALUE) {
                isLower = lowerBookPrice1 <= lowerBookPrice2;
            }

            return (isLower);
        }
        //-------------------------------------------------------------------------------------------------

        /// <summary>
        /// in: Title = "Shawshank redemption", ListPrice < 5000
        /// out: Not empty result
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void MA()
        {
            bool dataReady = false;
            bool condition = true;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true; //atach to the event that the data has already arrive
            };

            string searchKeyword = "The Shawshank redemption";
            int upperValue = 5000;

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            //Query writed in LinQ
            Query = from book in queryable
                        where
                          book.Keywords == searchKeyword && book.ListPrice.Amount <= upperValue
                        select book;

            //from book in queryable
            //where book.Keywords == searchKeyword
            //orderby book.Title
            //select book;
            //result = query.ToList<Book>();
            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);//utill dataredy is true

            EnqueueCallback(() =>
            {
                foreach (Common.DataTypes.Book b in Result)
                {
                    condition &= BookPriceInRange(b, NOT_VALUE, upperValue, PriceRangeOptions.LESS);
                };
            });

            EnqueueCallback(() => Assert.IsTrue(condition));

            EnqueueTestComplete();
        }

        /// <summary>
        /// in: Title = "Shawshank redemption", ListPrice > 3500
        /// out: Not empty result
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void MI()
        {
            bool dataReady = false;
            bool condition = true;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true; //atach to the event that the data has already arrive
            };

            string searchKeyword = "Shawshank redemption";
            int bottomValue = 1500;

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            //Query writed in LinQ
            Query = from book in queryable
                    where
                      book.Keywords == searchKeyword && book.ListPrice.Amount >= bottomValue
                    select book;

            //from book in queryable
            //where book.Keywords == searchKeyword
            //orderby book.Title
            //select book;
            //result = query.ToList<Book>();
            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);//utill dataredy is true

            EnqueueCallback(() =>
            {
                foreach (Common.DataTypes.Book b in Result)
                {
                    condition &= BookPriceInRange(b, bottomValue, NOT_VALUE, PriceRangeOptions.UPPER);
                };
            });

            EnqueueCallback(() => Assert.IsTrue(condition));

            EnqueueTestComplete();
        }

        /// <summary>
        /// in: Title = "Shawshank redemption", ListPrice > 3500
        /// out: Not empty result
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void MXM()
        {
            bool dataReady = false;
            bool condition = true;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true; //atach to the event that the data has already arrive
            };

            string searchKeyword = "Shawshank redemption";
            int bottomValue = 1500;
            int upperValue = 5000;

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            //Query writed in LinQ
            Query = from book in queryable
                    where
                      book.Keywords == searchKeyword && book.ListPrice.Amount >= bottomValue && book.ListPrice.Amount <= upperValue
                    select book;

            //from book in queryable
            //where book.Keywords == searchKeyword
            //orderby book.Title
            //select book;
            //result = query.ToList<Book>();
            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);//utill dataredy is true

            EnqueueCallback(() =>
            {
                foreach (Common.DataTypes.Book b in Result)
                {
                    condition &= BookPriceInRange(b, bottomValue, upperValue, PriceRangeOptions.BETWEEN);
                };
            });

            EnqueueCallback(() => Assert.IsTrue(condition));

            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        //------------------------------------------------------------------------------
        /*SELECT/WHERE*/
        #region SELECT/WHERE
        /// <summary>
        /// Harry Potter, not empty result
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SW1()
        {
            bool dataReady = false;
            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchKeyword = "Harry Potter";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                  book.Title == searchKeyword
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);
            EnqueueCallback(() => Assert.IsTrue(Result.Count > 0));

            EnqueueTestComplete();
        }

        /// <summary>
        /// Robot, All results having the text "Robot"
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SW2()
        {
            bool dataReady = false;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchKeyword = "Robot";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                  book.Title == searchKeyword
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);

            bool t = true;
            EnqueueCallback(() =>
            {

                foreach (Common.DataTypes.Book b in Result)
                {
                    // checking for searchKeyword in result's title
                    t = t && (b.Title.ToLower().Contains(searchKeyword.ToLower()) || searchKeyword.ToLower().Contains(b.Title.ToLower()));
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));


            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        /// <summary>
        /// in: Title = "Lord of the Rings"
        /// out: Not empty result
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SW1_1()
        {
            bool dataReady = false;
            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchString = "Lord of the Rings";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                  book.Title == searchString
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);
            EnqueueCallback(() => Assert.IsTrue(Result.Count > 0));

            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        //-------------------------------------------------------------------------------------------------
        /// <summary>
        /// in: Title = "Harry Potter"
        /// out: Every result contains the string "Harry Potter" in his Title
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SW2_1()
        {
            bool dataReady = false;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchString = "Harry Potter";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                  book.Title == searchString
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);

            bool t = true;
            EnqueueCallback(() =>
            {

                foreach (Common.DataTypes.Book b in Result)
                {
                    // checking for searchString in result's title
                    t = t && Contains(searchString, b.Title);//b.Title.Contains(searchString);
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));


            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        //-------------------------------------------------------------------------------------------------
        /// <summary>
        /// in: Title = "América"
        /// out: Every result contains the string "América" in his Title
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SWT1()
        {
            bool dataReady = false;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchString = "América";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                    book.Title == searchString
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);

            bool t = true;
            EnqueueCallback(() =>
            {

                foreach (Common.DataTypes.Book b in Result)
                {
                    // checking for searchString in result's title
                    t = t && Contains(searchString, b.Title);//b.Title.Contains(searchString);
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));


            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        //-------------------------------------------------------------------------------------------------
        /// <summary>
        /// in: Title = "Open Offise"
        /// out: Every result contains the string "Open Offise" in his Title
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SWTFO1()
        {
            bool dataReady = false;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchString = "Open Offise";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                    book.Title == searchString
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);

            bool t = true;
            EnqueueCallback(() =>
            {

                foreach (Common.DataTypes.Book b in Result)
                {
                    // checking for searchString in result's title
                    t = t && b.Title.Contains(searchString);
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));


            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        //-------------------------------------------------------------------------------------------------
        /// <summary>
        /// in: Title = "Mr/Mss Bossy"
        /// out: Every result contains the string "Mr/Mss Bossy" in his Title
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SWCE1()
        {
            bool dataReady = false;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchString = "Mr/Mss Bossy";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                    book.Title == searchString
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);

            bool t = true;
            EnqueueCallback(() =>
            {

                foreach (Common.DataTypes.Book b in Result)
                {
                    // checking for searchString in result's title
                    t = t && b.Title.Contains(searchString);
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));


            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        //-------------------------------------------------------------------------------------------------
        /// <summary>
        /// in: Title = "PS: I love you"
        /// out: Every result contains the string "PS: I love you" in his Title
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SWCE2()
        {
            bool dataReady = false;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchString = "PS: I love you";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                    book.Title == searchString
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);

            bool t = true;
            EnqueueCallback(() =>
            {

                foreach (Common.DataTypes.Book b in Result)
                {
                    // checking for searchString in result's title
                    t = t && Contains(searchString, b.Title);//b.Title.Contains(searchString);
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));


            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        //-------------------------------------------------------------------------------------------------
        /// <summary>
        /// in: Title = "1+2=3"
        /// out: Every result contains the string "1+2=3" in his Title
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SWCE3()
        {
            bool dataReady = false;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchString = "1+2=3";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                    book.Title == searchString
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);

            bool t = true;
            EnqueueCallback(() =>
            {

                foreach (Common.DataTypes.Book b in Result)
                {
                    // checking for searchString in result's title
                    t = t && Contains(searchString, b.Title);//b.Title.Contains(searchString);
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));


            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        //-------------------------------------------------------------------------------------------------
        /// <summary>
        /// in: Title = "Where are you Now?"
        /// out: Every result contains the string "Where are you Now?" in his Title
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SWCE4()
        {
            bool dataReady = false;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchString = "Where are you Now?";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                    book.Title == searchString
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);

            bool t = true;
            EnqueueCallback(() =>
            {

                foreach (Common.DataTypes.Book b in Result)
                {
                    // checking for searchString in result's title
                    t = t && Contains(searchString, b.Title);//b.Title.Contains(searchString);
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));


            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        //-------------------------------------------------------------------------------------------------
        /// <summary>
        /// in: Title = "100%HC"
        /// out: Every result contains the string "100%HC" in his Title
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SWCE5()
        {
            bool dataReady = false;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchString = "100%HC";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                    book.Title == searchString
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);

            bool t = true;
            EnqueueCallback(() =>
            {

                foreach (Common.DataTypes.Book b in Result)
                {
                    // checking for searchString in result's title
                    t = t && Contains(searchString, b.Title);//b.Title.Contains(searchString);
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));


            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        //-------------------------------------------------------------------------------------------------
        /// <summary>
        /// in: Title = "you&me"
        /// out: Every result contains the string "you&me" in his Title
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SWCE6()
        {
            bool dataReady = false;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchString = "you&me";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                    book.Title == searchString
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);

            bool t = true;
            EnqueueCallback(() =>
            {

                foreach (Common.DataTypes.Book b in Result)
                {
                    // checking for searchString in result's title
                    t = t && Contains(searchString, b.Title);//b.Title.Contains(searchString);
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));


            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        //-------------------------------------------------------------------------------------------------
        /// <summary>
        /// in: Title = "flirt m@il"
        /// out: Every result contains the string "flirt m@il" in his Title
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SWCE7()
        {
            bool dataReady = false;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchString = "flirt m@il";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                    book.Title == searchString
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);

            bool t = true;
            EnqueueCallback(() =>
            {

                foreach (Common.DataTypes.Book b in Result)
                {
                    // checking for searchString in result's title
                    t = t && Contains(searchString, b.Title);//b.Title.Contains(searchString);
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));


            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        //-------------------------------------------------------------------------------------------------
        /// <summary>
        /// in: Title = "Rule # 1"
        /// out: Every result contains the string "Rule # 1" in his Title
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SWCE8()
        {
            bool dataReady = false;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchString = "Rule # 1";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                    book.Title == searchString
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);

            bool t = true;
            EnqueueCallback(() =>
            {

                foreach (Common.DataTypes.Book b in Result)
                {
                    // checking for searchString in result's title
                    t = t && Contains(searchString, b.Title);//b.Title.Contains(searchString);
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));


            EnqueueTestComplete();
        }
        //-------------------------------------------------------------------------------------------------

        //-------------------------------------------------------------------------------------------------
        /// <summary>
        /// in: Title = "Make ea$y money!"
        /// out: Every result contains the string "Make ea$y money!" in his Title
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void SWCE9()
        {
            bool dataReady = false;

            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchString = "Make ea$y money!";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                    book.Title == searchString
                select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);

            bool t = true;
            EnqueueCallback(() =>
            {

                foreach (Common.DataTypes.Book b in Result)
                {
                    // checking for searchString in result's title
                    t = t && Contains(searchString, b.Title);//b.Title.Contains(searchString);
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));


            EnqueueTestComplete();
        }

        #endregion
        //------------------------------------------------------------------------------
        /*ORDER BY*/

        #region ORDERBY
        /// <summary>
        /// Get a list of books ordered ascendig by title and verify for 
        /// all items that ai<ai+1
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void OB1()
        {
            bool dataReady = false;
            this.SearchFinished += (s, e) =>
            {
                dataReady = true; //atach to the event that the data has already arrive
            };

            string searchKeyword = "Harry%20Potter";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);
            bool t = true;

            //Query writed in LinQ
            Query = from book in queryable
                        where
                          book.Keywords == searchKeyword
                        orderby book.Title

                        select book;//from book in queryable
            //where book.Keywords == searchKeyword
            //orderby book.Title
            //select book;
            //result = query.ToList<Book>();
            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);//utill dataredy is true
            int i = 0;

            EnqueueCallback(() =>
            {
                String[] titles = new String[Result.Count]; // string array

                foreach (Common.DataTypes.Book b in Result)// fill it with titles sorted as it is returned
                {
                    titles[i] = b.Title;
                    i++;
                };

                int j = 0;
                while ((j < i - 1) && t)
                {
                    t = String.Compare(titles[j], titles[j + 1]) <= 0;
                    j++;
                }

            });

            EnqueueCallback(() => Assert.IsTrue(t));

            EnqueueTestComplete();
        }

        /// <summary>
        /// 
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void OB2()
        {
            bool dataReady = false;
            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchKeyword = "Harry Potter";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);
            bool t = true;

            Query = from book in queryable
                    where book.Keywords == searchKeyword
                    orderby book.Title ascending, book.ListPrice descending
                    select book;



            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);
            int i = 0;

            EnqueueCallback(() =>
            {
                String[] auth = new String[Result.Count];

                foreach (Common.DataTypes.Book b in Result)
                {
                    auth[i] = b.Title;
                    i++;
                };

                int j = 0;
                while ((j < i - 1) && t)
                {
                    t = String.Compare(auth[j], auth[j + 1]) <= 0;
                    j++;
                }

            });

            EnqueueCallback(() => Assert.IsTrue(t));

            EnqueueTestComplete();
        }

        /// <summary>
        /// 
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void OB3()
        {
            bool dataReady = false;
            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchKeyword = "shawshank redemption";

            List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);
            bool t = true;

            Query = from book in queryable
                    where book.Keywords == searchKeyword
                    orderby book.ListPrice
                    select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);
            int i = 0;

            EnqueueCallback(() =>
            {
                while (i < (Result.Count - 1) && t)
                {
                    t &= IsBookPriceLower(Result[i], Result[i + 1]);
                    i++;
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));

            EnqueueTestComplete();
        }

        /// <summary>
        /// 
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void OB4()
        {
            bool dataReady = false;
            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchKeyword = "Harry potter";

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);
            bool t = true;

            Query = from book in queryable
                    where book.Keywords == searchKeyword
                    orderby book.ListPrice
                    select book;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);
            int i = 0;

            EnqueueCallback(() =>
            {
                while (i < (Result.Count - 1) && t) {
                    t &= IsBookPriceLower(Result[i], Result[i + 1]);
                    i++;
                }
            });

            EnqueueCallback(() => Assert.IsTrue(t));

            EnqueueTestComplete();
        }
        #endregion

        //------------------------------------------------------------------------------
        /*PAGE BY*/
        #region PAGEBY
        /// <summary>
        /// Get a book list, and test the first functionality
        /// </summary>
        /// 


        [TestMethod]
        [Asynchronous]
        public void F1()
        {
            bool dataReady = false;
            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchKeyword = "Harry Potter";

            //List<Common.DataTypes.Book> result = new List<Common.DataTypes.Book>();            

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                  book.Title == searchKeyword
                select book;

            QueryOption = QueryOptions.FIRST;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);


            EnqueueCallback(() =>
            {
                dataReady = false;
                int i = 0;
                QueryOption = QueryOptions.SIMPLE_QUERY;

                String[] titles = new String[20]; // string array, to keep the first 20 elements of the result

                foreach (Common.DataTypes.Book b in Result)// fill it with titles sorted as it is returned
                {
                    if (i < 20)
                    {
                        titles[i] = b.Title;
                        i++;
                    }
                    else
                    {
                        break;
                    }
                };

                //Query.First();

                EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
                EnqueueConditional(() => dataReady);

                EnqueueCallback(() => Assert.IsTrue(titles[0].CompareTo(BookResult.Title) == 0));
            }
            );


            EnqueueTestComplete();
        }

        /// <summary>
        /// Get a book list, and test the last functionality
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void L1()
        {
            bool dataReady = false;
            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchKeyword = "shawshank redemption";

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query =
                from book in queryable
                where
                  book.Title == searchKeyword
                select book;

            QueryOption = QueryOptions.LAST;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);


            EnqueueCallback(() =>
            {
                dataReady = false;
                QueryOption = QueryOptions.SIMPLE_QUERY;

                string lastTitle = Result[Result.Count - 1].Title;

                EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
                EnqueueConditional(() => dataReady);

                //Compare the last title in the array with  the first book title in the result of Query.Last()
                EnqueueCallback(() => Assert.IsTrue(lastTitle.CompareTo(BookResult.Title) == 0));

            }
        );
            EnqueueTestComplete();
        }


        /// <summary>
        /// Get a book list, and test if skip(n) get the list without the first n elements
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void S1()
        {
            bool dataReady = false;
            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchKeyword = "Harry Potter";

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query = from book in queryable
                    where
                    book.Title == searchKeyword
                    select book;

            Query2 = Query.Skip(10);
            QueryOption = QueryOptions.DOUBLE_QUERY;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);


            EnqueueCallback(() =>
            {
                dataReady = false;
                //int i = 0;

                QueryOption = QueryOptions.SIMPLE_QUERY;

                string titlePositionTen = Result[10].Title; // string array

                EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
                EnqueueConditional(() => dataReady);

                EnqueueCallback(() => Assert.IsTrue(titlePositionTen.CompareTo(Result2.ElementAt(0).Title) == 0));
            }
           );
            EnqueueTestComplete();
        }



        /// <summary>
        /// Get a book list, and test if take(n) get the list with the first n elements
        /// </summary>
        [TestMethod]
        [Asynchronous]
        public void C1()
        {
            bool dataReady = false;
            this.SearchFinished += (s, e) =>
            {
                dataReady = true;
            };

            string searchKeyword = "Shawshank redemption";

            var provider = new AmazonProvider();
            provider.AmazonKey = AmazonKey;
            provider.ResultLanguage = QueryLanguage;

            var queryable = new AmazonQuery<Common.DataTypes.Book>(provider);

            Query = from book in queryable
                    where
                    book.Title == searchKeyword
                    select book;

            Query2 = Query.Take(10);

            QueryOption = QueryOptions.DOUBLE_QUERY;

            EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
            EnqueueConditional(() => dataReady);


            EnqueueCallback(() =>
            {
                dataReady = false;
                int i = 0;
                QueryOption = QueryOptions.SIMPLE_QUERY;

                String[] titles1 = new String[Result.Count]; // string array

                foreach (Common.DataTypes.Book b in Result)// fill it with titles sorted as it is returned
                {
                    titles1[i] = b.Title;
                    i++;
                };


                List<Common.DataTypes.Book> ResultTen = Result2;

                String[] titles2 = new String[ResultTen.Count]; // string array
                i = 0;

                foreach (Common.DataTypes.Book b in ResultTen)// fill it with titles sorted as it is returned
                {
                    titles2[i] = b.Title;
                    i++;
                };

                bool t = true;

                int minCant = Math.Min(Result.Count, ResultTen.Count);

                for (i = 0; i < minCant; i++)
                    t = t && (titles1[i].CompareTo(titles2[i]) == 0);

                EnqueueCallback(() => GetLinqWorker<Common.DataTypes.Book>().Start());
                EnqueueConditional(() => dataReady);

                EnqueueCallback(() => Assert.IsTrue(t));
            }
           );
            EnqueueTestComplete();
        }


        #endregion

        #region helpers
        Thread GetLinqWorker<T>()
        {
            return new Thread(new ThreadStart(GetLINQResult));
        }

        private void GetLINQResult()
        {
            if (QueryOption == QueryOptions.SIMPLE_QUERY)
            {
                Result = Query.ToList<Common.DataTypes.Book>();
            }
            else if (QueryOption == QueryOptions.DOUBLE_QUERY)
            {
                Result = Query.ToList<Common.DataTypes.Book>();
                Result2 = Query2.ToList<Common.DataTypes.Book>();
            }
            else if (QueryOption == QueryOptions.FIRST) {
                Result = Query.ToList<Common.DataTypes.Book>();
                BookResult = Query.First();
            }
            else if (QueryOption == QueryOptions.LAST)
            {
                Result = Query.ToList<Common.DataTypes.Book>();
                BookResult = Query.Last();
            }
            
            _mainDispatcher.BeginInvoke(delegate()
            {
                //OnSearchCompleted(new SearchCompletedEventArgs(result));
                //TODO::Arreglar problema de tipos que retorna y aarreglar
                //SearchCompleted(Query.ToList<T>());
                OnSearchFinished(new SearchFinishedEventArgs());
            });
        }

        public delegate void SearchFinishedHandler(object sender, SearchFinishedEventArgs e);

        public event SearchFinishedHandler SearchFinished;

        protected virtual void OnSearchFinished(SearchFinishedEventArgs e)
        {
            if (SearchFinished != null)
                SearchFinished(this, e);
        }

        #endregion
    }

    public class SearchFinishedEventArgs
    {
        //IEnumerable<T> _result;

        public SearchFinishedEventArgs()//(IEnumerable<T> result)
        {
            //_result = result;
        }


    }

    //add this Test to proy Web
}
